Writing a Point and Click Adventure Game

© 2005, Janet Terra

author contact:

janetterra@yahoo.com

NL136 Home

::::::::::::::::::::::::::::::::::::::::::::::::::::

Eddie Version 6

Comalspeech.dll

Point-and-Click

Dr. Strange Text

Length of Internet File

Automatic File Updating

API Corner

Wire 1.0 on the Horizon

::::::::::::::::::::::::::::::::::::::::::::::::::::

Submission Guildlines

Newsletter Help

Index


Introduction

The first adventure games were text only. Surely you remember

West of House

You are in an open field west of a big white house, with a boarded front door.

There is a small mailbox here.

>Open mailbox

Opening the small mailbox reveals a leaflet.

>Read leaflet

(Taken)

"WELCOME TO ZORK!

Later on, graphics were added to the text based adventure game. These graphics were not an integral part of the game, but merely served as illustrations. Apple's Mystery House is credited with being the first adventure game to include graphics. Gameplay still relied heavily upon the written descriptions of locations, objects and events.

One of the earliest games to shift away from the written description to more visual clues was Sierra's King's Quest. Rather than reading about the well, the well was actually visible. Once the object was taken, that object was removed from the graphic display. A textbox was still required for user input, as the player was still forced to type

>Take apple

Okay. You place the apple in your inventory.

Hoping to decrease player frustration resulting from both tedious typing and non-recognized user entries, game designers opted for total mouse driven play. Typically, two comboxes were used. The first contained an array of verbs, the second an array of nouns. Only options available to that location and inventory list were displayed. Still, the verb - noun combination was sometimes klutzy and always distracting. Many players resented the 'walkthrough' ease of play delivered by the dropdown lists. These games were not well received.

Fortunately, technology favored the gaming industry. Low-resolution graphics gave way to Hi-resolution graphics and sprite animation allowed true Point and Click games. Text messaging, especially in the form of either character or narrative dialog, took a back seat to the mouse cursor against the graphic background. Rather than

>Walk west

A steep mountain range blocks your way. You cannot move west.

the user sees the granite border and the mouse cursor fails to give the familiar west arrow appearance.

When interacting with objects, what used to be

>Open chest

You find 23 gold coins and one healing potion

is now a series of pictures showing a closed treasure chest, an open filled treasure chest, and an open empty treasure chest. The inventory list now includes the 23 gold pieces and the healing potion.

Point and Click in Liberty BASIC

Can you make a 'Point and Click' game in Liberty BASIC? Sure you can. All you need are the graphics, the sprites, the cursors, a scripting and parsing routine, and a bit of imagination.

Each location is assigned a background graphic. Graphics are both memory and disk intensive. One way to reduce memory and file size is to use .gif files rather than .bmp. Liberty BASIC has no native command to load .gif files, but non-bitmap graphics are easily loaded into LB programs using Alyce Watson's jpeg.dll. Each location gif is given the name of the corresponding room or cell number (e.g., cell001.gif, cell002.gif). The sprites are also in .gif format and also named by assigned number (e.g., obj0001.gif, obj0002.gif).

The actual 'Point and Click' is accomplished with the when mouseMove command and the spritescollides command. A simple 2 pixel (one pixel for the sprite, the other for the mask) is used to travel with the cursor. It is this simple 2 pixel sprite (obj0000) that initiates the collision list.

    #main.gb1, "When mouseMove [FindObjects]"

In the [FindObjects] block of code, look for a sprite collision.

    CurX = MouseX
    CurY = MouseY
    #main.gb1, "Spritexy obj0000 ";CurX;" ";CurY
    #main.gb1, "Drawsprites"
    #main.gb1, "Spritecollides obj0000 CollisionList$"

The Custom Cursor

When no sprite collision is taking place, the cursor remains the usual arrow. When a collision is taking place, the program informs the user than the object is 'clickable' by changing to a grabbing hand cursor.

    If Instr(CollisionList$, "obj") > 0 Then
        CurHandle = LoadCursor(32649)
        Call ObjectDesc CollisionList$
        OldList$ = CollisionList$
        #main.gb1, "When leftButtonUp [SelectObject]"
    End If

If the player then left clicks the mouse, the object is selected. Otherwise, as the player moves away from the sprite and collision is no longer detected, the cursor returns to the normal arrow shape.

Movements out of the current location to a new location are also visually depicted using a custom cursor and sprites. Four egress sprites are loaded, one at each of the four edges. If the cursor & obj0000 collides with an egress sprite, the cursor changes to the appropriate direction arrow.

Invisible Sprites

Even invisible sprites initiate collisions. This allows the egress sprites to remain invisible to the player. The egress sprites must be physically moved from the available graphic box space if collision is not desired. This would be the case when the player cannot move in a particular direction, or if an object has been added to the player's inventory. Moving the sprite out of the graphicbox area is accomplished with negative x or y coordinates.

Adding to the Inventory

To conserve file space and memory, the same masked .gif pic is used for both sprite and inventory. By drawing the .gif pic using the midheight for y, the mask is not visible to the viewer. Not all sprite objects can be taken. Some are there for descriptive purposes only.

Location Information

A sequential text file is used to store data for each of the locations. As the file is read, the information is stored in the array cellInfo$(). Information is extracted using the Word$ function with the pipe (|) as the deliminator. The information stored in each line entry is

1:SHORT DESCRIPTION

2:FIRST VISIT TO ROOM

3:RETURN VISIT TO ROOM

4:AFTER SPECIAL EVENT

5:EGRESS '0 2 0 0

6:OBJECT 1 '(1 230 250)

7:OBJECT 2 '(2 280 250)

8:OBJECT 3 '(3 220 121)

9:OBJECT 4 '(0 0 0)

The first 3 elements are just descriptions. The 4th element can be called later in the game. An example would be a room containing a burning fireplace, but later that fire was doused. Number 5, the egress information, tells which room or cell is entered by that exiting in that direction. The order of egresses are N, E, S, W. In the above example, the north, south and west exits are blocked. Moving east places the player in cell #2. The object information contains the number of the sprite, the x coordinate of the sprite, and the 6 coordinate of the sprite. This demo allows a maximum of four sprite objects per room.

Object Information

The second sequential text file contains the information for each sprite object. It is this file that contains all the information necessary for game play. As with the location information, information is first read from the text file using Line Input. Later, the Word$() function with the pipe (|) deliminator is used to extract specific information about that object. The information includes

1:Objn-Short Description

2:Detailed Description

3:Take Description

4:InvBox

5:InvCoords

6:UseRoom

7:NumberValidResponsesNonUseRoom

8:Response1

9:Response2

10:Response3

11:SpriteRequiredInUseRoom 0=No,1=Yes

12:NumberValidResponses

13:Response1

14:Response2

15:Response3

16:InventoryItemRequired 0=No,1=Yes

17:NumberValidResponses

18:Response1

19:Response2

20:Response3

21:ToBeDetermined 0=No,1=Yes

22:NumberValidResponses

23:Response1

24:Response2

25:Response3

26:USEITEMNumberOfCommandsToFollow

27+:The sequence of commands

Elements 1 - 3 are descriptive. Elements 4 and 5 are necessary to tell which inventory graphicbox to draw the .gif and the upper left x and y coordinates necessary to hide the mask. Element 6 stores the room in which the object can be used. Element 7 tells how many (3 maximum) responses can be randomly called if the player attempts to use that item in any other room. Elements 8, 9 and 10 hold those responses. It might be necessary for another object to be available in that room for this object to be used. The number of that sprite object is held in element 11 (0 = no sprite object required). Again, if the sprite object is not available in the use room, a number of responses might be given (elements 12 -15). It might be necessary to have a second item in inventory before an object can be used. That second item is stored in element 16 and the available responses when that second item is lacking being stored in elements 17 -20. Because this demo was meant to be built upon, a third block of similar information was added without any particular assignment. All objects have these 25 items separated by the pipe deliminator. If all conditions are met, (i.e., the right room and any other required object available), the object can be used. A number of commands are then executed. The number of commands is stored in element 26. A loop is set up to extract and execute commands 27 forth.

Parsing and Scripting

Execution of the commands are accomplished using Select Case. Each command is followed by any necessary arguments, separated by a hyphen (-) deliminator.

    For i = 1 to nCommands
        Parse$ = Word$(ObjectInfo$(nObj), 26 + i, "|")
        Command = Val(Word$(Parse$, 1, ":"))
        Command$ = Word$(Parse$, 2, ":")
        Select Case Command 'The Execution of the Scripted Commands
            Case 1 'Print
                handle$ = Word$(Command$, 1, "-")
                Print #handle$, Word$(Command$, 2, "-")
            Case 2 'Clear Inv Screen
                handle$ = "#main.inv";Val(Command$)
                Print #handle$, "Getbmp InvObj 0 0 80 80"
                Print #handle$, "Cls; Fill Buttonface; Flush"
            Case 3 'Redraw Inventory Item
                handle$ = "#main.inv";Val(Command$)
                Print #handle$, "Drawbmp InvObj 0 0; Flush"
            Case 4 'Add / Remove a Visible Object
                VisObj = Val(Word$(Command$, 1))
                VisState = Val(Word$(Command$, 2))
                VisibleObject(VisObj) = VisState
                SpriteObject$ = "obj";ZeroFiller$(VisObj, 4)
                x = Val(Word$(Command$, 3))
                y = Val(Word$(Command$, 4))
                #main.gb1, "Spritexy ";SpriteObject$;" ";x;" ";y
                #main.gb1, "Drawsprites"
            Case 5 'DelayTime
                Call Sleep Val(Command$)
        End Select
    Next i

By parsing carefully constructed scripted text, the adventure game with 1000 locations uses the same program as this demo holding just 3 locations. All that's needed are more entries to the cellInfo.txt file and the objectInfo.txt file. The two commands, Word$() and Select Case are used extensively throughout this demo. Feel free to adapt the code to meet your needs.

More Resources

Where can you learn more about loading non bitmap pic files with the jpeg.dll? [Alyce's Restaurant]

Where can you learn more about sprites? The Sprite Byte Series by Alyce Watson (LB Newsletters 119 - Present)

Where can you learn more about loading custom cursors? Custom Cursors With LoadCursorFromFile (LB Newsletter #135)

Where can you learn more about parsing and scripted language? Scripting Language Tutorial (LB Newsletter #98), Comal Dll: MS Agent and Liberty BASIC (LB Newsletter #126), Chat Challenge (LB Newsletter #133)


DEMO

The file PointClickAdvJLT.bas, with associated image and text files, is included in the zipped archive of this newsletter.


NL136 Home

::::::::::::::::::::::::::::::::::::::::::::::::::::

Eddie Version 6

Comalspeech.dll

Point-and-Click

Dr. Strange Text

Length of Internet File

Automatic File Updating

API Corner

Wire 1.0 on the Horizon

::::::::::::::::::::::::::::::::::::::::::::::::::::

Submission Guildlines

Newsletter Help

Index